package com.kunsan.compose.net

import android.app.Application
import android.os.Build
import cn.aidisplay.elderly.library.network.ApiDSL
import com.github.kittinunf.fuel.core.FuelManager
import com.github.kittinunf.fuel.core.Headers
import com.github.kittinunf.fuel.core.interceptors.LogRequestInterceptor
import com.github.kittinunf.fuel.core.interceptors.LogResponseInterceptor
import com.github.kittinunf.fuel.gson.jsonBody
import com.github.kittinunf.fuel.gson.responseObject
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.fuel.httpPost
import com.kunsan.compose.BuildConfig
import com.kunsan.compose.data.UserDataManager
import com.kunsan.compose.utils.DigestUtil
import com.kunsan.compose.utils.GsonUtils

object ApiClient {


    const val CONTENT_TYPE_APPLICATION_JSON = "application/json"
    const val CONTENT_TYPE_FORM_DATA = "multipart/form-data; boundary=custom-boundary"

    private var netWorkParams: NetWorkParams =
        NetWorkParams(
            platform = PlatformType.ANDROID,
            baseUrl = NetWorkConfig.API_OAUTH_URL
        )

    /**
     * 隐私政策授权
     */
    private var authPolicy: Boolean = false

    val gson = GsonUtils.getGson()

    var apiInternalListener: ((code: Int?, msg: String?, desc: String?) -> Unit?)? = null

    init {
        // 接口请求日志拦截器
        FuelManager.instance.addRequestInterceptor(LogRequestInterceptor)
        // 接口响应日志拦截器
        FuelManager.instance.addResponseInterceptor(LogResponseInterceptor)
    }

    /**
     * 注册全局接口请求异常状态监听，返回码参考接口文档
     * */
    fun Application.registerApiListener(listener: (code: Int?, msg: String?, desc: String?) -> Unit) {
        apiInternalListener = listener
    }

    fun initialize(
        platformType: PlatformType,
        baseUrl: String = NetWorkConfig.API_OAUTH_URL
    ) {
        netWorkParams = NetWorkParams(platformType, baseUrl)
    }


    inline fun <reified T> get(
        path: String,
        parameters: List<Pair<String, Any?>> = arrayListOf(),
        baseUrl: String? = null,
        callback: ApiDSL<T>.() -> Unit
    ) {
        val dsl = ApiDSL<T>().apply(callback)
        val url = genBaeUrl(path, baseUrl)
        url.httpGet(parameters)
            .header(generateHeader())
            .timeout(NetworkConstants.TIME_OUT)
            .timeoutRead(NetworkConstants.READ_TIME_OUT)
            .responseObject<ResultData<T>> { request, _, result ->
                result.fold(
                    success = {
                        when (it.code) {
                            NetworkConstants.API_RESPONSE_SUCCESS_CODE -> {
                                dsl.ok?.invoke(it)
                            }

                            NetworkConstants.API_AUTH_EXPIRED_CODE,
                            NetworkConstants.API_AUTH_TOKEN_EXPIRED_CODE -> {
                            }

                            else -> {
                                dsl.fail?.invoke(it)
                            }
                        }
                        apiInternalListener?.invoke(it.code, it.msg, it.desc)
                    },
                    failure = {
                        val sysError =
                            ResultData<T>(-1, "request failure", "请求异常，请检查网络设置", null)
                        dsl.fail?.invoke(sysError)
                        apiInternalListener?.invoke(sysError.code, sysError.msg, sysError.desc)
                    }
                )
            }
    }

    /**
     * @param path 接口地址
     * @param params 接口请求参数
     * @param baseUrl 可空，自定义当前接口服务器地址
     * @param callback 回调
     *
     * 普通类请求
     * Api.post<Data>(path,params){}
     * 请求列表时，由于泛型擦除原因，需要具体化对象类，可构建一个类继承ArrayList
     * class DataList : ArrayList<Data>()
     * 然后 Api.post<DataLIst>(path,params){}  来构建请求
     * */

    inline fun <reified T> post(
        path: String,
        params: MutableMap<String, Any?> = mutableMapOf(),
        baseUrl: String? = null,
        callback: ApiDSL<T>.() -> Unit
    ) {
        val dsl = ApiDSL<T>().apply(callback)
        val url = genBaeUrl(path, baseUrl)
        url.httpPost()
            .header(generateHeader())
            .jsonBody(params, gson)
            .timeout(NetworkConstants.TIME_OUT)
            .timeoutRead(NetworkConstants.READ_TIME_OUT)
            .responseObject<ResultData<T>> { request, _, result ->
                result.fold(
                    success = {
                        when (it.code) {
                            NetworkConstants.API_RESPONSE_SUCCESS_CODE -> {
                                dsl.ok?.invoke(it)
                            }

                            NetworkConstants.API_AUTH_EXPIRED_CODE,
                            NetworkConstants.API_AUTH_TOKEN_EXPIRED_CODE -> {
                            }

                            else -> {
                                dsl.fail?.invoke(it)
                            }
                        }
                        apiInternalListener?.invoke(it.code, it.msg, it.desc)
                    },
                    failure = {
                        val sysError =
                            ResultData<T>(-1, "request failure", "请求异常，请检查网络设置", null)
                        dsl.fail?.invoke(sysError)
                        apiInternalListener?.invoke(sysError.code, sysError.msg, sysError.desc)
                    }
                )
            }
    }

    fun genBaeUrl(path: String, baseUrl: String? = null): String {
        var url = netWorkParams.baseUrl + path
        baseUrl?.let {
            url = it + path
        }
        return url
    }


    data class Login(
        var abd: String
    )

    data class Profile(
        var abd: String
    )

    enum class Path(
        val url: String,
        val params: MutableMap<String, Any?> = hashMapOf(),
        val base: String? = null
    ) {
        LOGIN("", hashMapOf()),
        PROFILE("", hashMapOf())
    }


    private fun generateHeader(params: MutableMap<String, Any?>): Map<String, Any> {
        params["appId"] = UserDataManager.getClientId()
        params["timestamp"] = System.currentTimeMillis()
        params["deviceId"] = AppInternalInformation.getDeviceId()
        params["deviceModel"] = AppInternalInformation.getDeviceModel()
        params["platform"] = netWorkParams.platform.platformType
        return hashMapOf()
    }

    fun generateHeader(contentType: String? = CONTENT_TYPE_APPLICATION_JSON): Map<String, String> {
        // 校验参数
        val signedParams: MutableMap<String, Any?> = hashMapOf()
        val token = UserDataManager.getUserToken()
        if (authPolicy) {
            signedParams["deviceId"] = AppInternalInformation.getDeviceId()
        }
        signedParams["appId"] = UserDataManager.getClientId()
        signedParams["platform"] = netWorkParams.platform.platformType
        signedParams["timestamp"] = System.currentTimeMillis()
        // 一般头部参数，不参与校验
        val headerParams: MutableMap<String, String> = hashMapOf()
        headerParams["sign"] = DigestUtil.getRequestCheckSum(signedParams, "sign")
        headerParams["deviceName"] = Build.MODEL
        headerParams["versionCode"] = "${BuildConfig.APP_VERSION_CODE}"
        headerParams["versionName"] = BuildConfig.APP_VERSION_NAME
        headerParams["uid"] = UserDataManager.getUserId()
        headerParams["token"] = token
        headerParams["clientId"] = "${netWorkParams.platform.platformType}"
        headerParams["Authorization"] = if (token.isEmpty()) {
            token
        } else {
            "Bearer $token"
        }
        headerParams[Headers.CONTENT_TYPE] = contentType ?: CONTENT_TYPE_APPLICATION_JSON
        signedParams.map {
            headerParams[it.key] = it.value.toString()
        }
        return headerParams
    }
}